import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { FindAllDto, UpdateUserDto } from './dto/update-user.dto';
import { User } from './entities/user.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, In, Like } from 'typeorm';
import { ApiException } from '../common/filter/http-exception/api.exception';
import { ApiErrorCode } from '../common/enums/api-error-code.enum';
import { Role } from '../role/entities/role.entity';
import { JWT_User } from '../auth/dto/update-auth.dto';
import { CacheService } from 'src/cache/cache.service';
import { format } from 'date-fns';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
    @InjectRepository(Role)
    private roleRepository: Repository<Role>,
    private cacheService: CacheService,
    // private authService: AuthService,
  ) {}
  async create(createUserDto: CreateUserDto) {
    const { username, roleIds, ...Value } = createUserDto;
    const existUser = await this.userRepository.findOne({
      where: { username },
    });
    if (existUser)
      throw new ApiException('用户已存在', ApiErrorCode.USER_NOTEXIST);

    try {
      const roles = await this.roleRepository.find({
        where: { id: In(roleIds) },
      });
      const user = this.userRepository.create({ ...Value, roles, username });
      await this.userRepository.save(user);
      return '注册成功';
    } catch (error) {
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  async findOne(username: string) {
    const user = await this.userRepository.findOne({
      where: { username },
      relations: ['roles'],
    });
    if (!user) throw new ApiException('用户不存在', ApiErrorCode.USER_NOTEXIST);
    return user;
  }

  async findById(id: number) {
    const user = await this.userRepository.findOne({
      where: { id },
      relations: ['roles'],
    });
    if (!user) throw new ApiException('用户不存在', ApiErrorCode.USER_NOTEXIST);
    return user;
  }
  // 把 refreshToken 写入数据库
  async updateRefreshToken(id: number, refreshToken: string) {
    const user = await this.userRepository.findOne({ where: { id } });
    if (!user) throw new ApiException('用户不存在', ApiErrorCode.USER_NOTEXIST);
    user.refreshToken = refreshToken;
    await this.userRepository.save(user);
    return user;
  }

  //user.service.ts
  async findPermissionNames(data: JWT_User): Promise<string[]> {
    const arr: string[][] = [];
    for (const roleId of data.roleIds) {
      const cache = await this.cacheService.get<string[]>(
        `role_${roleId}_permissions`,
      );
      if (cache) {
        arr.push(cache);
      }
    }
    if (arr.length > 0 && arr.length === data.roleIds.length) {
      const permissions = arr
        .map((item) => item)
        .flat()
        .map((item) => item);

      return [...new Set(permissions)];
    }
    // 缓存中没有角色信息
    const roles = await this.roleRepository.find({
      where: { id: In(data.roleIds) },
      relations: ['permissions'],
    });
    if (roles) {
      for (const role of roles) {
        await this.cacheService.set(
          `role_${role.id}_permissions`,
          role.permissions.flatMap((item) => item.name),
          60 * 60 * 24,
        );
      }
      const permissions = roles.map((item) => item.permissions).flat();
      const permissionNames = permissions.map((item) => item.name);

      return [...new Set(permissionNames)];
    } else {
      return [];
    }
  }

  async findAll(params: FindAllDto): Promise<{
    records: Partial<User>[];
    total: number;
    current: number;
    size: number;
  }> {
    const [data, total] = await this.userRepository.findAndCount({
      skip: (params.current - 1) * params.size,
      take: params.size,
      relations: ['roles'],
      where: params.username ? { username: Like(`%${params.username}%`) } : {},
    });
    if (!data) throw new ApiException('用户不存在', ApiErrorCode.USER_NOTEXIST);
    return {
      records: data.map((role) => {
        return {
          id: role.id,
          username: role.username,
          permissions: role.roles.map((permission) => {
            return {
              id: permission.id,
              name: permission.name,
            };
          }),
          createTime: format(role.create_time, 'yyyy-MM-dd HH:mm:ss'), //格式化时间
        };
      }),
      total: total,
      current: params.current,
      size: params.size,
    };
  }

  // 更新
  async update(id: number, updateUserDto: UpdateUserDto) {
    const { username, roleIds, ...Value } = updateUserDto;
    const existUser = await this.userRepository.findOne({
      where: { username },
    });
    if (existUser && existUser.id !== id)
      throw new ApiException('用户已存在', ApiErrorCode.USER_NOTEXIST);

    try {
      let role: Role[] = [];
      if (roleIds) {
        const roles = await this.roleRepository.find({
          where: { id: In(roleIds) },
        });
        role = roles;
      }
      const user = await this.userRepository.preload({
        id,
        ...Value,
        roles: role,
        username,
      });
      if (!user)
        throw new ApiException('用户不存在', ApiErrorCode.USER_NOTEXIST);
      await this.userRepository.save(user);
      return '更新成功';
    } catch (error) {
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  // 删除
  async remove(id: number) {
    const user = await this.userRepository.findOne({ where: { id } });
    if (!user) throw new ApiException('用户不存在', ApiErrorCode.USER_NOTEXIST);
    await this.userRepository.delete(id);
    return '删除成功';
  }
}
